<?php

namespace App\Services;

use Gate;
use Illuminate\Support\Facades\Lang;
use Route;
use App\Menu;
use App\Services\Interfaces\MenuServiceInterface;

class MenuService implements MenuServiceInterface
{
    const MODELS = [
        'manage', //管理
        'statistics', //报表
        'system', //系统
    ];
    const GROUPS = [
        'project',   // 微信号管理
        'channel',   // 渠道管理
        'card',      // SIM卡柜
        'password',  // 微系统管理
        'report',    //渠道报表
    ];
    /**
     * @var array $_menus
     * <code>
     *  $_menus = [
     *    'system' => array(
     *       [
     *        'key' => 'account',
     *        'title' => '账号管理',
     *        'group' => 'system',
     *        ...
     *       ],
     *      .......
     *    ),
     *    'project' => array(...),
     *    'customer' => array(...),
     *  ];
     * </code>
     */
    protected $_menus;
    protected $_count = 0;

    public function __construct()
    {
        $this->_init();
    }

    public function getMenus(string $_group_name = ''):array
    {
        assert(
            empty($_group_name) OR in_array($_group_name, self::GROUPS),
            "Unknown group name: $_group_name"
        );
        return
            empty($_group_name)
                ? $this->_menus
                : ($this->_menus[$_group_name] ?? []);
    }

    /**
     * @param $_group_name
     * @return \Generator
     * <code>
     * foreach ($menuService->genMenusByGroup('system') as $sysMenu) {
     *   echo $sysMenu->title;
     *   // ..........
     * }
     * </code>
     */
    public function genMenusByGroup(string $_group_name):\Generator
    {
        assert(in_array($_group_name, self::GROUPS), "Unknow group name: $_group_name");
        foreach ($this->_menus[$_group_name] as $menu) {
            yield $menu;
        }
    }

    public static function registerRoutes()
    {
        $menus = Menu::all();
        foreach ($menus as $menu) {
            $group_name = $menu->group;
            if (in_array($group_name, self::GROUPS)) {
                $controller = ucfirst($menu->group) . 'Controller';
                $action = lcfirst($menu->key);
                if (class_exists("\\App\\Http\\Controller\\Resources\\$controller")) {
                    $use_name = $controller . '@' . $action;
                } else {
                    $use_name = 'HomeController@index';
                }
                $uri = "/{$menu->model}/{$menu->group}{$menu->uri}";
                // 分别注册菜单的别名
                Route::get($uri,
                    ['uses' => $use_name,
                        'as' => "$group_name.$action"]);
            }
        }
        // 注册获取菜单的API
        Route::get('/api/menus', ['middleware' => 'json',
            'uses' => function () {
                return (new self)->getMenus();
            }]);
    }

    public function getMenuUri(string $_key):string
    {
        if (stringContains($_key, '.')) {
            list($group, $key) = explode('.', $_key);
        } else if (stringContains($_key, ':')) {
            list($group, $key) = explode(':', $_key);
        } else {
            $group = '';
            $key = $_key;
        }

        if (empty($group)) {
            // 没有给组名,只按照key名查找
//            $result = 
        } else {
            assert(in_array($group, self::GROUPS), 'Unknown group name:' . $group);

        }
    }

    public function getCount():int
    {
        return $this->_count ?? 0;
    }

    /**
     * 初始化
     * 从数据库中获取所有的菜单
     */
    protected function _init()
    {
        $un_group_data = Menu::all();
        foreach ($un_group_data as $key => $value) {
            if ($value->model == 'manage') {
                $un_group_data[$key]->orderNum = 1;
            }
            if ($value->model == 'statistics') {
                $un_group_data[$key]->orderNum = 2;
            }
            if ($value->model == 'system') {
                $un_group_data[$key]->orderNum = 3;
            }
        }
        $un_group_data = array_sort($un_group_data, function ($value) {
            return $value['orderNum'];
        });
        /**
         * @var array $un_sort_arr
         * [ $group_name => [] ]
         */
        $un_sort_arr = [];
        $count = 0;
        foreach ($un_group_data as $menu) {
            if (in_array($menu->model, self::MODELS)) {
                if (!isset($un_sort_arr[$menu->model])) {
                    $un_sort_arr[$menu->model] = [
                        'key' => $menu->model,
                        'title' => trans('menus.models.' . $menu->model),
                        'list' => [],
                    ];
                }
                if (in_array($menu->group, self::GROUPS)
                    // 检查当前登录用户是否有权限显示此菜单 (通过MenuPolicy->show()方法检查)
                    && Gate::allows('show', $menu)
                ) {
                    if (!isset($un_sort_arr[$menu->model]['list'][$menu->group])) {
                        $un_sort_arr[$menu->model]['list'][$menu->group] = [
                            'key' => $menu->group,
                            'title' => trans('menus.groups.' . $menu->group),
                            'list' => [],
                        ];
                    }
                    array_push($un_sort_arr[$menu->model]['list'][$menu->group]['list'], $menu);
                    $count++;
                }
            }
        }
        array_walk($un_sort_arr, function ($_model) {
            array_walk($_model['list'], function ($_group) {
                usort($_group['list'], function ($_a, $_b) {
                    $a_order = intval($_a->order) or 0;
                    $b_order = intval($_b->order) or 0;
                    if ($a_order === $b_order) {
                        return 0;
                    }
                    return $a_order < $b_order ? -1 : 1;
                });
                return $_group;
            });
            return $_model;
        });
        foreach ($un_sort_arr as &$value) {
            $value['list'] = array_values($value['list']);
        }
        $this->_menus = array_values($un_sort_arr);
        $this->_count = $count;
    }
}
